// ==UserScript== // @name Modal Image in rule(rule34图片查看器 水果玉米版) // @namespace http://tampermonkey.net/ // @version 20241127 // @description Add a modal image and thumbnails vertical-carrousel to rule34, add functions of drag img and resize img, rule34图片查看器, 修改版 // @author falaz, hzx // @match https://rule34.xxx/index.php?page=po* // @icon https://www.google.com/s2/favicons?domain=rule34.xxx // @grant GM_download // @license MIT // ==/UserScript== /*jshint esversion: 6 */ // @ts-check // original author is falaz, hzx just add functios orinal https://sleazyfork.org/en/scripts/390625-modal-image-in-rule\ function getFileNameFromURL(url) { // 检查是否包含问号并去掉?及其后面的内容 let cleanedUrl = url.includes('?') ? url.split('?')[0] : url; // 获取最后一个斜杠后的内容 let fileName = cleanedUrl.substring(cleanedUrl.lastIndexOf('/') + 1); return fileName; } class Falaz { /** * Like querySelector, but small * @param {String} selector * @param {Element|Document} element * @returns {HTMLElement} */ q(selector, element = document) { return element.querySelector(selector); } /** * Like querySelectorAll, but small * @param {String} selector * @param {Element|Document} element * @returns */ qa(selector, element = document) { return element.querySelectorAll(selector); } } class Modal { constructor(document, dp) { this.pointer = 0; this.dp = dp; this.infinityScroll = new InfinityScroll(document, dp); /** * @property {Media[]} medias */ this.medias = this.infinityScroll.getMedias(document, 0); this.thumbsGallery = new ThumbsGallery(this.medias); this.createModalNode(document, this.thumbsGallery.render()); this.bodyParent = F.q('body'); this.visible = false; } createConfigBar(){ return `
` } createModalNode(document, extraDiv=null) { const div = document.createElement("div"); const css = document.createElement("style"); div.innerHTML = ` `; css.innerHTML = ".content {display: flex; flex-wrap: wrap; gap: 5px;}" + "span[data-nosnippet] {display: none;}" + "#modal-container{background: #000000a8;width: 100%;height: 100%;position: fixed;z-index: 10;}" + "#modal{height: 90%;width: 80%;background: transparent;padding: 0% 5%;margin: 2% 5% 2% 0;position: fixed}" + "#modal img{width: auto;border: none;vertical-align: middle;height: 100%;margin: 0 auto;display:block;}" + "#modal video{width: 100%;height:100%}"+ "#modal-container #thumbGallery{float:right;overflow-y: scroll;height: 900px;} #modal-container #thumbGallery ul{list-style:none}"+ "#modal-container .gallery-item{cursor: pointer;}"+ '#navigationModal{margin-bottom: 0px;font-size: 20px;color: white;display: flex;justify-content: center;bottom: 0px;width: 100%; position:absolute}'+ '#navigationModal svg:hover g g {fill: white;}'+ '.fluid_video_wrapper video{cursor:default!important}'+ '@media (max-width: 1024px) {#thumbGallery {display: none;} #modal{width:100%;padding:0%;overflow-x:scroll}}'+ '#modal-container button {border-radius: 25px; border: none; background: #1abc9c; margin-left: 10px}'; if(debug){ css.innerHTML+= "img,video{filter:blur(30px)}"; } document.body.prepend(div); document.head.prepend(css); this.modalContainer = F.q("#modal-container"); this.modal = F.q("#modal"); this.infinityScroll.nextPage =this.infinityScroll.getNextPageHref(document); } createButtons(){ return ` ` } /** * @param {Media} media */ async render(media) { if (!this.modalContainer) { this.createModalNode(document,this.thumbsGallery.render()); } if (media.src == "Retry") { await this.reloadMediaSrc(media); } if (media.type == "video") { this.modal.innerHTML = ``; F.q('#modalVideo').volume = this.getCurrentVolume(); F.q('#modalVideo').onvolumechange = e=>this.saveCurrentVolume(e.target.volume); fluidPlayer(document.querySelector('#modal video'),{ layoutControls:{ autoPlay:true, allowDownload:true, loop:true, fillToContainer: true } }) F.q('#modal video').loop = true } else { this.modal.innerHTML = ``; // hzx修改=========== this.innerImg = F.q("img", this.modal ); let img = this.innerImg; let scale = 1; let originX = 0; let originY = 0; let isDragging = false; let startX, startY; img.addEventListener('wheel', (event) => { event.preventDefault(); const rect = img.getBoundingClientRect(); const offsetX = event.clientX - rect.left; const offsetY = event.clientY - rect.top; const delta = Math.sign(event.deltaY) * -0.1; const newScale = Math.min(Math.max(0.5, scale + delta), 3); originX = (originX - offsetX) * (newScale / scale) + offsetX; originY = (originY - offsetY) * (newScale / scale) + offsetY; scale = newScale; img.style.transform = `translate(${originX}px, ${originY}px) scale(${scale})`; }); img.addEventListener('mousedown', (event) => { event.preventDefault(); isDragging = true; startX = event.clientX; startY = event.clientY; img.style.cursor = 'grabbing'; }); window.addEventListener('mouseup', () => { event.preventDefault(); isDragging = false; img.style.cursor = 'grab'; }); window.addEventListener('mousemove', (event) => { event.preventDefault(); if (!isDragging) return; const dx = event.clientX - startX; const dy = event.clientY - startY; originX += dx; originY += dy; startX = event.clientX; startY = event.clientY; img.style.transform = `translate(${originX}px, ${originY}px) scale(${scale})`; }); this.resetImage = function() { scale = 1; originX = 0; originY = 0; img.style.transform = `translate(0, 0) scale(${scale})`; } this.downloadImage = function() { GM_download({url:img.src, name: getFileNameFromURL(img.src)}); } // hzx修改结束 } this.modalContainer.style.display = "block"; this.visible = true; this.toggleBodyScroll(false); modalObj.scrollIntoCurrentMedia(); } toggleBodyScroll(visible){ this.bodyParent.style.overflow = visible?'inherit':'hidden'; } getCurrentVolume(){ return localStorage.volume? localStorage.volume: 0.0; } /** * Attach to event video.onvolumechange * @param {number} value */ saveCurrentVolume(value){ localStorage.volume = value; } async getNextPage() { if (!this.infinityScroll.nextSended) { this.infinityScroll.nextSended = true; const docResponse = await this.infinityScroll.getNextPage(); if (docResponse) { const medias = this.infinityScroll.getMedias( docResponse, this.medias.length ); this.addMedias(medias); this.infinityScroll.nextSended = false; }else{ c('The page requested is on the medias'); } } } close() { if (!this.modalContainer) { this.createModalNode(document); } try { this.modal.querySelector("video").pause(); } catch (e) {} this.modalContainer.style.display = "none"; this.toggleBodyScroll(true); this.visible = false; } nextMedia() { if (this.pointer < this.medias.length - 1) { this.pointer++; this.render(this.medias[this.pointer]); } else { this.getNextPage(); this.pointer++; this.render(this.medias[this.pointer]); } } goToMedia(index){ if(index